package com.xhj.mybatis.reflection;

import java.lang.reflect.*;
import java.util.Arrays;

/**
 * TypeParameterResolver
 *
 * @author XJks
 * @description 类型参数解析器，用于在运行时解析泛型类型参数的实际类型。TODO:解决 泛型实际类型（字段/方法返回值/参数）的推断问题，供 Reflector/MetaClass 在类型分析时使用。
 */
public class TypeParameterResolver {

    /**
     * 解析字段的实际类型（包括泛型参数的实际类型）。
     *
     * @param field   需要解析的字段对象
     * @param srcType 字段所属类的类型（可能带有泛型参数）
     * @return 字段的实际类型（如 List<String> 中的 String）
     */
    public static Type resolveFieldType(Field field, Type srcType) {
        // 获取字段声明时的类型（可能是泛型类型，如 T、List<T> 等）
        Type fieldType = field.getGenericType();
        // 获取声明该字段的类（即这个字段是在哪个类里定义的）
        Class<?> declaringClass = field.getDeclaringClass();
        // 递归解析字段类型，将泛型变量替换为实际类型，得到最终的字段类型
        return resolveType(fieldType, srcType, declaringClass);
    }

    /**
     * 解析方法的返回值类型，返回实际类型（包括泛型参数的实际类型）。
     *
     * @param method  方法对象
     * @param srcType 方法所属类的类型（可能是带泛型参数的类型）
     * @return 返回值的实际类型
     */
    public static Type resolveReturnType(Method method, Type srcType) {
        // 获取方法的返回类型（可能包含泛型参数），如 List<T>、T 等
        Type returnType = method.getGenericReturnType();
        // 获取声明该方法的类对象，比如这个方法是在哪个类里定义的
        Class<?> declaringClass = method.getDeclaringClass();
        // 递归解析返回类型，将泛型变量替换为实际类型，得到最终的返回类型
        return resolveType(returnType, srcType, declaringClass);
    }

    /**
     * 解析方法参数类型，返回每个参数的实际类型（包括泛型参数的实际类型）。
     *
     * @param method  方法对象
     * @param srcType 方法所属类的类型（可能是带泛型参数的类型）
     * @return 参数类型数组，每个元素为实际类型
     */
    public static Type[] resolveParamTypes(Method method, Type srcType) {
        // 获取方法所有参数的声明类型（可能包含泛型，如 List<T>、T 等）
        Type[] paramTypes = method.getGenericParameterTypes();
        // 获取声明该方法的类对象（即这个方法是在哪个类里定义的）
        Class<?> declaringClass = method.getDeclaringClass();
        // 创建一个数组，用于存放解析后的参数实际类型
        Type[] result = new Type[paramTypes.length];
        // 遍历每一个参数类型，逐个进行解析
        for (int i = 0; i < paramTypes.length; i++) {
            // 对每个参数类型递归解析，将泛型变量替换为实际类型
            result[i] = resolveType(paramTypes[i], srcType, declaringClass);
        }
        // 返回所有参数的实际类型数组
        return result;
    }

    /**
     * 递归解析类型，支持 TypeVariable、ParameterizedType、GenericArrayType。
     * TODO:该方法的作用类似于 SpringMVC 框架的前端控制器 DispatcherServlet，用于对类型变量 type 的解析进行分发，根据不同的类型调用不同的解析方法。
     *
     * @param type           需要解析的类型（可能是泛型变量、参数化类型、泛型数组或普通类型）
     * @param srcType        源类型（通常是带泛型参数的类或接口）
     * @param declaringClass 声明该类型的类（即 type 是在哪个类里声明的）
     * @return 解析后的实际类型（如将 T 解析为 String）
     */
    private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
        // 如果 type 是类型变量（如 T），需要递归解析出它的实际类型
        if (type instanceof TypeVariable) {
            // 调用 resolveTypeVar 方法解析类型变量
            return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
            // 如果 type 是参数化类型（如 List<T>），需要递归解析其每个类型参数
        } else if (type instanceof ParameterizedType) {
            // 调用 resolveParameterizedType 方法解析参数化类型
            return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
            // 如果 type 是泛型数组类型（如 T[]），需要递归解析其组件类型
        } else if (type instanceof GenericArrayType) {
            // 调用 resolveGenericArrayType 方法解析泛型数组类型
            return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
        } else {
            // 如果 type 是普通类型（如 String、int），直接返回，无需解析
            return type;
        }
    }

    /**
     * 解析泛型数组类型（如 T[]）。
     *
     * @param genericArrayType 泛型数组类型（如 T[]、List<String>[] 等）
     * @param srcType          源类型（通常是带泛型参数的类或接口）
     * @param declaringClass   声明该类型的类
     * @return 解析后的实际类型
     */
    private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
        // 获取数组的组件类型，比如 T[] 的组件类型是 T，List<String>[] 的组件类型是 List<String>
        Type componentType = genericArrayType.getGenericComponentType();
        Type resolvedComponentType = null;
        // 判断组件类型的实际类型，并递归解析
        if (componentType instanceof TypeVariable) {
            // 如果组件类型是类型变量（如 T），递归解析出它的实际类型
            resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
        } else if (componentType instanceof GenericArrayType) {
            // 如果组件类型本身还是泛型数组类型（如 T[][]），递归解析
            resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
        } else if (componentType instanceof ParameterizedType) {
            // 如果组件类型是参数化类型（如 List<String>），递归解析
            resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
        }
        // 如果解析后的组件类型是普通类（如 String.class），直接返回对应的数组类型（如 String[].class）
        if (resolvedComponentType instanceof Class) {
            // 通过反射创建一个长度为0的数组对象，并获取其Class对象（如 String[].class）
            return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
        } else {
            // 如果不是普通类（可能还是泛型），则返回自定义的泛型数组类型实现
            return new GenericArrayTypeImpl(resolvedComponentType);
        }
    }

    /**
     * 解析参数化类型（如 List<T>）。
     *
     * @param parameterizedType 参数化类型（如 List<T>、Map<K, V> 等）
     * @param srcType           源类型（通常是带泛型参数的类或接口）
     * @param declaringClass    声明该类型的类
     * @return 解析后的参数化类型
     */
    private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
        // 获取原始类型（如 List），即去掉泛型参数后的类
        Class<?> rawType = (Class<?>) parameterizedType.getRawType();
        // 获取参数化类型中的所有类型参数（如 List<T> 中的 T）
        Type[] typeArgs = parameterizedType.getActualTypeArguments();
        // 创建一个新数组，用于存放解析后的实际类型参数
        Type[] args = new Type[typeArgs.length];
        // 遍历每一个类型参数，逐个进行递归解析
        for (int i = 0; i < typeArgs.length; i++) {
            // 如果类型参数是类型变量（如 T），递归解析出它的实际类型
            if (typeArgs[i] instanceof TypeVariable) {
                args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
                // 如果类型参数本身又是参数化类型（如 List<T> 中的 T 其实是 List<U>），递归解析
            } else if (typeArgs[i] instanceof ParameterizedType) {
                args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
                // 如果类型参数是通配符类型（如 ? extends Number），递归解析
            } else if (typeArgs[i] instanceof WildcardType) {
                args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
                // 如果类型参数是普通类型（如 String），直接赋值
            } else {
                args[i] = typeArgs[i];
            }
        }
        // 返回自定义的参数化类型实现对象，包含原始类型和解析后的实际类型参数
        return new ParameterizedTypeImpl(rawType, null, args);
    }

    /**
     * 解析通配符类型（如 ? extends Number）。
     *
     * @param wildcardType   通配符类型（如 ?、? extends Number、? super String）
     * @param srcType        源类型（通常是带泛型参数的类或接口）
     * @param declaringClass 声明该类型的类
     * @return 解析后的通配符类型
     */
    private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
        // 递归解析通配符的下界（如 ? super String 的 String），
        // 可能下界本身也是类型变量或参数化类型，需要进一步解析
        Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);

        // 递归解析通配符的上界（如 ? extends Number 的 Number），
        // 也可能是类型变量或参数化类型，需要进一步解析
        Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);

        // 用解析后的上下界，构造自定义的 WildcardType 实现类，返回新的通配符类型
        return new WildcardTypeImpl(lowerBounds, upperBounds);
    }

    /**
     * 递归解析通配符类型的上下界。
     *
     * @param bounds         上下界数组（可能是上界或下界）
     * @param srcType        源类型（通常是带泛型参数的类或接口）
     * @param declaringClass 声明类型的类（即这些界限是在这个类里声明的）
     * @return 解析后的上下界数组（每个元素都被解析为实际类型）
     */
    private static Type[] resolveWildcardTypeBounds(Type[] bounds, Type srcType, Class<?> declaringClass) {
        // 创建一个新数组，用于存放解析后的类型
        Type[] result = new Type[bounds.length];
        // 遍历每一个上界或下界
        for (int i = 0; i < bounds.length; i++) {
            // 如果界限是类型变量（如 T），递归解析为实际类型
            if (bounds[i] instanceof TypeVariable) {
                result[i] = resolveTypeVar((TypeVariable<?>) bounds[i], srcType, declaringClass);
                // 如果界限是参数化类型（如 List<T>），递归解析
            } else if (bounds[i] instanceof ParameterizedType) {
                result[i] = resolveParameterizedType((ParameterizedType) bounds[i], srcType, declaringClass);
                // 如果界限本身是通配符类型（如 ? extends Number），递归解析
            } else if (bounds[i] instanceof WildcardType) {
                result[i] = resolveWildcardType((WildcardType) bounds[i], srcType, declaringClass);
                // 如果界限是普通类型（如 String），直接赋值
            } else {
                result[i] = bounds[i];
            }
        }
        // 返回解析后的上下界数组
        return result;
    }

    /**
     * 解析类型变量（如 T），找到实际类型。
     *
     * @param typeVar        类型变量（如 T）
     * @param srcType        源类型（通常是带泛型参数的类或接口）
     * @param declaringClass 声明类型变量的类（即 T 是在哪个类里声明的）
     * @return 解析后的实际类型（如将 T 解析为 String）
     */
    private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
        // 用于存放递归查找的结果
        Type result;
        // 当前正在处理的类
        Class<?> clazz;
        // 判断 srcType 是普通类还是参数化类型（如 List<String>）
        if (srcType instanceof Class) {
            // 如果是普通类，直接强转
            clazz = (Class<?>) srcType;
        } else if (srcType instanceof ParameterizedType) {
            // 如果是参数化类型，先取出原始类型（如 List），再强转为 Class
            ParameterizedType parameterizedType = (ParameterizedType) srcType;
            clazz = (Class<?>) parameterizedType.getRawType();
        } else {
            // 如果不是以上两种，抛出异常（一般不会出现）
            throw new IllegalArgumentException("The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
        }
        // 如果当前类就是声明类型变量的类
        if (clazz == declaringClass) {
            // 获取类型变量的上界（如 T extends Number），如果没写上界，默认是 Object
            Type[] bounds = typeVar.getBounds();
            if (bounds.length > 0) {
                // 返回第一个上界（Java 语法只允许一个上界）
                return bounds[0];
            }
            // 没有上界，返回 Object.class
            return Object.class;
        }

        // 递归查找父类，看看父类有没有声明该类型变量
        Type superclass = clazz.getGenericSuperclass();
        result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
        if (result != null) {
            // 如果在父类找到了实际类型，直接返回
            return result;
        }

        // 递归查找所有接口，看看接口有没有声明该类型变量
        Type[] superInterfaces = clazz.getGenericInterfaces();
        for (Type superInterface : superInterfaces) {
            result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
            if (result != null) {
                // 如果在接口找到了实际类型，直接返回
                return result;
            }
        }
        // 如果父类和接口都找不到，返回 Object（泛型擦除的默认类型）
        return Object.class;
    }

    /**
     * 在父类或接口中查找类型变量的实际类型。
     *
     * @param typeVar        需要解析的类型变量（如 T）
     * @param srcType        当前类的类型（可能是参数化类型，如 List<String>）
     * @param declaringClass 声明 typeVar 的类（即 T 是在哪个类里声明的）
     * @param clazz          当前正在处理的类
     * @param superclass     当前类的父类或接口（可能是参数化类型或普通类）
     * @return 解析后的实际类型，找不到返回 null
     */
    private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
        // 如果父类或接口是参数化类型（如 List<String>）
        if (superclass instanceof ParameterizedType) {
            ParameterizedType parentAsType = (ParameterizedType) superclass; // 强转为参数化类型
            Class<?> parentAsClass = (Class<?>) parentAsType.getRawType(); // 获取原始类型（如 List）
            TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters(); // 获取父类声明的所有类型变量（如 T）

            // 如果 srcType 也是参数化类型，需要将父类的类型变量用子类的实际类型参数替换
            if (srcType instanceof ParameterizedType) {
                parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
            }

            // 如果父类就是声明 typeVar 的类
            if (declaringClass == parentAsClass) {
                // 遍历父类的所有类型变量
                for (int i = 0; i < parentTypeVars.length; i++) {
                    // 如果找到了和 typeVar 相同的类型变量
                    if (typeVar.equals(parentTypeVars[i])) {
                        // 返回父类参数化类型中对应位置的实际类型参数
                        return parentAsType.getActualTypeArguments()[i];
                    }
                }
            }
            // 如果父类是声明类的父类（或祖先），递归查找
            if (declaringClass.isAssignableFrom(parentAsClass)) {
                // 递归解析父类的类型变量
                return resolveTypeVar(typeVar, parentAsType, declaringClass);
            }
            // 如果父类或接口是普通类，并且是声明类的父类（或祖先）
        } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
            // 递归解析父类的类型变量
            return resolveTypeVar(typeVar, superclass, declaringClass);
        }
        // 如果都找不到，返回 null
        return null;
    }

    /**
     * 类型变量替换，将父类的类型变量用子类的实际类型参数替换。
     * <p>
     * 例如：假设有如下类结构
     * class Parent<T> {}
     * class Child extends Parent<String> {}
     * 当我们解析 Parent<T> 在 Child 上的实际类型时，需要把 T 替换为 String。
     *
     * @param srcType    子类的参数化类型（如 Child 实例对应的 Parent<String>）
     * @param srcClass   子类的 Class（如 Child.class）
     * @param parentType 父类的参数化类型（如 Parent<T>）
     * @return 替换后的参数化类型（如 Parent<String>）
     */
    private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass, ParameterizedType parentType) {
        // 获取父类参数化类型的所有类型参数（如 Parent<T> 的 T）
        Type[] parentTypeArgs = parentType.getActualTypeArguments();
        // 获取子类参数化类型的所有实际类型参数（如 Parent<String> 的 String）
        Type[] srcTypeArgs = srcType.getActualTypeArguments();
        // 获取子类声明的所有类型变量（如 Child<T, U> 的 T、U）
        TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();
        // 创建一个新数组，用于存放替换后的父类类型参数
        Type[] newParentArgs = new Type[parentTypeArgs.length];
        // 标记是否有类型参数发生了替换
        boolean noChange = true;
        // 遍历父类的每一个类型参数
        for (int i = 0; i < parentTypeArgs.length; i++) {
            // 如果父类的类型参数是类型变量（如 T）
            if (parentTypeArgs[i] instanceof TypeVariable) {
                // 遍历子类声明的类型变量，尝试找到同名的类型变量
                for (int j = 0; j < srcTypeVars.length; j++) {
                    // 如果子类的类型变量和父类的类型变量相等
                    if (srcTypeVars[j].equals(parentTypeArgs[i])) {
                        // 说明可以用子类的实际类型参数替换父类的类型变量
                        noChange = false; // 有替换发生
                        newParentArgs[i] = srcTypeArgs[j]; // 替换
                    }
                }
            } else {
                // 如果父类的类型参数不是类型变量（如 String），直接赋值
                newParentArgs[i] = parentTypeArgs[i];
            }
        }
        // 如果所有类型参数都没有发生替换，直接返回原参数化类型
        // 否则，返回一个新的参数化类型实现，类型参数为替换后的 newParentArgs
        return noChange ? parentType : new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
    }

    /**
     * 私有构造方法，防止实例化。
     */
    private TypeParameterResolver() {
        super();
    }

    /**
     * 参数化类型实现类（如 List<String>）。
     */
    static class ParameterizedTypeImpl implements ParameterizedType {
        /**
         * 原始类型（如 List）
         */
        private Class<?> rawType;
        /**
         * 拥有者类型（如外部类）
         */
        private Type ownerType;
        /**
         * 实际类型参数（如 String）
         */
        private Type[] actualTypeArguments; // 实际类型参数（如 String）

        public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
            super();
            this.rawType = rawType;
            this.ownerType = ownerType;
            this.actualTypeArguments = actualTypeArguments;
        }

        @Override
        public Type[] getActualTypeArguments() {
            return actualTypeArguments;
        }

        @Override
        public Type getOwnerType() {
            return ownerType;
        }

        @Override
        public Type getRawType() {
            return rawType;
        }

        @Override
        public String toString() {
            return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments=" + Arrays.toString(actualTypeArguments) + "]";
        }
    }

    /**
     * 通配符类型实现类（如 ? extends Number）。
     */
    static class WildcardTypeImpl implements WildcardType {
        /**
         * TODO:
         *      1.WildcardType接口常用于解析泛型中的通配符类型，如 List<? extends Number> 或 Map<String, ?> 中的 ?，这些通配符类型可以有上界（extends）或下界（super）。
         *        实际上 Java 语法规定通配符最多只能有一个上界或一个下界，因此这两个数组要么长度为 0，要么长度为 1（JDK 保持数组形式是历史/一致性原因）。
         *      2.区别于 {@link TypeVariable}（类型变量）允许多个上界，通配符不允许交叉类型上界（没有 ? extends A & B 这种写法）。
         *      3.三种常见形态与“默认界”
         *          <table border="1" cellpadding="4" cellspacing="0">
         *          <caption>通配符类型常见形态与默认界</caption>
         *              <tr>
         *                <th>通配符写法</th><th>意义</th><th>getUpperBounds()（上界）</th><th>getLowerBounds()（下界）</th>
         *              </tr>
         *              <tr>
         *                <td>?（无界通配）</td><td>是某个未知类型</td><td>[Object.class]（默认上界Object）</td><td>[]（无下界）</td>
         *              </tr>
         *              <tr>
         *                <td>? extends U</td><td>上界是U或其子类（协变）</td><td>[U]</td><td>[]</td>
         *              </tr>
         *              <tr>
         *                <td>? super L</td><td>下界是L或其父类（逆变）</td><td>[Object.class]</td><td>[L]</td>
         *              </tr>
         *          </table>
         *      3.关键记忆点
         *         - 没写上界 ⇒ 上界就是 Object。
         *         - 没写下界 ⇒ 下界数组为空。
         *         - 不可能同时写 extends 和 super。
         *         - 上/下界可以是任意引用类型（包括参数化类型），但不能是交叉类型列表。
         */
        private Type[] lowerBounds;
        private Type[] upperBounds;

        WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
            super();
            this.lowerBounds = lowerBounds;
            this.upperBounds = upperBounds;
        }

        @Override
        public Type[] getLowerBounds() {
            return lowerBounds;
        }

        @Override
        public Type[] getUpperBounds() {
            return upperBounds;
        }
    }

    /**
     * 泛型数组类型实现类（如 T[]）。
     */
    static class GenericArrayTypeImpl implements GenericArrayType {
        private Type genericComponentType; // 组件类型

        GenericArrayTypeImpl(Type genericComponentType) {
            super();
            this.genericComponentType = genericComponentType;
        }

        @Override
        public Type getGenericComponentType() {
            return genericComponentType;
        }
    }
}
